package com.simple.dsrouter.strategy.impl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.springframework.util.PatternMatchUtils;

import com.simple.dsrouter.config.DataSourceConfig;
import com.simple.dsrouter.config.DataSourceConfig.DataSourceType;
import com.simple.dsrouter.holder.DataSourceContextHolder;
import com.simple.dsrouter.util.ValidateUtils;

/**
 * 实现按属性取模的Master-Slave路由策略
 */
public class ModMasterSlaveRouteStrategy extends ModRouteStrategy {

	/**
	 * 读的方法列表，采用正则表达式匹配，仅支持*
	 * */
	private List<String> readMethodPatterns;

	/**
	 * 随机数，随机选择一个Slave
	 * */
	private Random random = new Random();

	@Override
	protected void routeForModValue(int modKey, Object target, Method method, Object[] args) {
		List<DataSourceConfig> dataSources = dataSourceKeyMap.get(modKey);
		String methodName = method.getName();
		if (dataSources.size() == 1) {
			// always return master
			String masterDataSource = dataSources.get(0).getDatasourceId();
			if (logger.isDebugEnabled()) {
				logger.debug("method: " + methodName + " --> reslove routing parameter mod value: " + modKey + " --> routing to master datasource: " + masterDataSource);
			}
			DataSourceContextHolder.setCurrentDataSourceKey(masterDataSource);
			return;
		}

		// 多个datasource，选择性路由
		boolean isReadMethod = false;
		for (String pattern : readMethodPatterns) {
			if (PatternMatchUtils.simpleMatch(pattern, methodName)) {
				isReadMethod = true;
				break;
			}
		}

		// 按数据源类型分组
		List<DataSourceConfig> readDataSources = new ArrayList<DataSourceConfig>(dataSources.size());
		List<DataSourceConfig> writeDataSources = new ArrayList<DataSourceConfig>(dataSources.size());
		for (DataSourceConfig dataSource : dataSources) {
			if (DataSourceType.READ.name().equalsIgnoreCase(dataSource.getType())) {
				readDataSources.add(dataSource);
			} else if (DataSourceType.WRITE.name().equalsIgnoreCase(dataSource.getType())) {
				writeDataSources.add(dataSource);
			} else {
			}
		}

		// write to master
		if (!isReadMethod) {
			String masterDataSource = writeDataSources.get(0).getDatasourceId();
			if (logger.isDebugEnabled()) {
				logger.debug("write method: " + methodName + " --> reslove routing parameter mod value: " + modKey + " --> routing to master datasource: " + masterDataSource);
			}
			DataSourceContextHolder.setCurrentDataSourceKey(masterDataSource);
			return;
		}
		// 如果是read方法
		routeSlaveDataSource(readDataSources, modKey, target, method, args);
	}

	protected void routeSlaveDataSource(List<DataSourceConfig> dataSources, int modKey, Object target, Method method, Object[] args) {
		// 从slave列表中随机选择一个
		int index = random.nextInt(dataSources.size());
		String slaveDataSourceKey = dataSources.get(index).getDatasourceId();
		if (logger.isDebugEnabled()) {
			logger.debug("read method: " + method.getName() + " --> reslove routing parameter mod value: " + modKey + " --> routing to slave datasource: " + slaveDataSourceKey);
		}
		DataSourceContextHolder.setCurrentDataSourceKey(slaveDataSourceKey);
	}

	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		if (readMethodPatterns == null) {
			throw new IllegalArgumentException("readMethodPatterns  arugment must not be null");
		}
	}

	public void setReadMethodPatterns(List<String> readMethodPatterns) {
		this.readMethodPatterns = ValidateUtils.validInterceptMethodPatterns(readMethodPatterns);
	}

}